package com.ruoyi.system.controller;


import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.domain.FileModel;
import com.ruoyi.system.domain.FileLibraryModel;
import com.ruoyi.system.domain.dto.DeleteDto;
import com.ruoyi.system.domain.dto.KnowledgeBaseDto;
import com.ruoyi.system.service.FileLibraryService;
import com.ruoyi.system.service.FileService;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.KnowledgeBaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @Auther Zhipeng Lyu
 * @Date 2023/12/15 14:57
 * @Description 知识库管理接口
 **/

@RestController
@RequestMapping("/knowledge_base")
public class KnowledgeBaseController {


    @Autowired
    private KnowledgeBaseService knowledgeBaseService;
    @Autowired
    private FileLibraryService fileLibraryService;
    @Autowired
    private FileService fileService;
    @Autowired
    private ISysConfigService configService;
    @PostMapping("/add")
    public R add(@RequestBody KnowledgeBaseDto knowledgeBaseDto){
        //获取用户提供的知识库名称
        String kbName = knowledgeBaseDto.getKnowledgeBaseName();
        if (kbName == null){
            return R.fail("必须提供文档库名称");
        }
        // 生成uuid作为知识库的名称
        String uuid = UUID.randomUUID().toString();

        //向chatchat后端请求构建新的知识库
        boolean ccRes = knowledgeBaseService.CreateKnowledgeBase(uuid);
        if (!ccRes){
            return R.fail("知识库新建失败！");
        }
        // 存储文档库信息到mysql表中
        FileLibraryModel fileLibraryModel = new FileLibraryModel();
        fileLibraryModel.setLibName(kbName);
        fileLibraryModel.setKbName(uuid);
        fileLibraryModel.setUserId(SecurityUtils.getUserId());
        fileLibraryModel.setCreator(SecurityUtils.getUserId());
        fileLibraryModel.setGmtCreated(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        fileLibraryModel.setIsPublic(1);
        fileLibraryModel.setIsDeleted(0);


        boolean res = fileLibraryService.save(fileLibraryModel);
        if (res){
            return R.ok(null,"知识库新建成功，并已保存到文档库表中！");
        }else {
            return R.fail("文档库表保存失败！");
        }
    }

    @PostMapping("/temp_add")
    public R tempAdd(@RequestBody KnowledgeBaseDto knowledgeBaseDto) throws UnsupportedEncodingException {
        //获取用户提供的源知识库名称和临时知识库名称
        Long sourceKbId = knowledgeBaseDto.getSourceKbId();
        if (sourceKbId == null){
            return R.fail("必须提供源文档库id");
        }
        //获取对应知识库名称
        FileLibraryModel fileLibraryModel = fileLibraryService.getById(sourceKbId);
        if(fileLibraryModel == null) return R.fail("此id不存在！");
        String kbName = fileLibraryModel.getKbName();
        String tempKbName = knowledgeBaseDto.getTempKnowledgeBaseName();
        List<String> fileNames = knowledgeBaseDto.getFileNames();
        if (kbName == null){
            return R.fail("必须提供源文档库名称");
        } else if (tempKbName == null) {
            return R.fail("必须提供临时文档库名称");
        } else if (fileNames == null) {
            return R.fail("必须提供文档名称列表");
        }
        // 生成uuid以作为临时知识库名称
        String uuid = UUID.randomUUID().toString();
        knowledgeBaseDto.setKnowledgeBaseName(kbName);
        knowledgeBaseDto.setTempKnowledgeBaseName(uuid);
        // 查找对应文件名在知识库中的名称，有可能是uuid
        List<String> fileUuids = new ArrayList<>();
        // 用于文件名和文件uuid对照的map
        Map<String ,String> fileName2uuid = new HashMap<>();
        for(String fileName : fileNames) {
            FileModel equalFileModel = fileService.lambdaQuery()
                    .eq(FileModel::getLibraryId, sourceKbId)
                    .eq(FileModel::getIsDeleted, 0)
                    .eq(FileModel::getFileName, fileName)
                    .one();
            String fileUuid = "";
            if (equalFileModel != null) {
                fileUuid = equalFileModel.getKbName();
            } else {
                return R.fail("知识库中缺少对应的文件！文件名：" + fileName);
            }
            fileUuids.add(fileUuid);
            fileName2uuid.put(fileName, fileUuid);
        }
        //将输入的文件名称列表修改为uuid列表
        knowledgeBaseDto.setFileNames(fileUuids);
        //向chatchat后端请求构建新的知识库
        boolean ccRes = knowledgeBaseService.CreateTempKnowledgeBase(knowledgeBaseDto);
        if (!ccRes){
            return R.fail("临时知识库新建失败！");
        }
        // 存储文档库信息到mysql表中
        FileLibraryModel fileLibraryModel2 = new FileLibraryModel();
        fileLibraryModel2.setLibName(tempKbName);
        fileLibraryModel2.setKbName(uuid);
        fileLibraryModel2.setUserId(SecurityUtils.getUserId());
        fileLibraryModel2.setCreator(SecurityUtils.getUserId());
        fileLibraryModel2.setGmtCreated(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        fileLibraryModel2.setIsPublic(1);
        fileLibraryModel2.setIsDeleted(0);
        boolean res = fileLibraryService.save(fileLibraryModel2);

        Long tempKbId = fileLibraryModel2.getId();
        // 存储文档信息到mysql表中

        List<FileModel> fileModelList = new ArrayList<>();
        String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"));
        String baseURL = configService.selectConfigByKey("sys.m36b.address");
        for (String filename : fileNames) {
            if (filename == null) {
                return R.fail("必须提供文档名称");
            }
            FileModel fileModel = new FileModel();
            fileModel.setFileName(filename);
            fileModel.setLibraryId(tempKbId);
            fileModel.setUserId(SecurityUtils.getUserId());
            fileModel.setCreator(SecurityUtils.getUserId());
            fileModel.setGmtCreated(time);
            String uuid1 = fileName2uuid.get(filename);
            fileModel.setKbName(uuid1);
            fileModel.setIsDeleted(0);
            fileModel.setUrl(baseURL + "/knowledge_base/download_doc?knowledge_base_name=" + URLEncoder.encode(tempKbName
                    , "UTF-8") + "&file_name=" + URLEncoder.encode(fileModel.getKbName(), "UTF-8"));
            fileModelList.add(fileModel);
        }
        boolean res2 = fileService.saveBatch(fileModelList);
        Map<String, Long> data = new HashMap<>();
        data.put("kbId", tempKbId);
        if (res && res2){
            return R.ok(data,"临时知识库新建成功，文档库和文档信息同步保存成功！");
        } else if (!res) {
            return R.fail("文档库表保存失败！");
        } else {
            return R.fail("文档表保存失败！");
        }
    }

    @PostMapping("/delete")
    public R delete(@RequestBody DeleteDto deleteDto){
        //获取用户提供的文档库ID
        Long id = deleteDto.getId();
        String knowledgeBaseName = deleteDto.getKnowledgeBaseName();
        // 查询到的对应数据库的id和kbName
        List<Long> ids = new ArrayList<>();
        List<String> kbNames = new ArrayList<>();
        if (id != null || knowledgeBaseName != null){
            if (id != null){
                // 检查用户删除权限
                checkPublicPermission(deleteDto.getId());

                //获取对应知识库名称
                FileLibraryModel fileLibraryModel = fileLibraryService.getById(id);
                if(fileLibraryModel == null) return R.fail("此id不存在！");
                String kbName = fileLibraryModel.getKbName();
                ids.add(id);
                kbNames.add(kbName);

            }else {
                String libName = knowledgeBaseName;
                List<FileLibraryModel> fileLibraryModels = fileLibraryService.lambdaQuery()
                        .eq(FileLibraryModel::getLibName, libName)
                        .eq(FileLibraryModel::getIsDeleted, 0)
                        .list();
                if (fileLibraryModels != null) {
                    for(FileLibraryModel fileLibraryModel : fileLibraryModels) {
                        Long tempId = fileLibraryModel.getId();
                        String tempKbName = fileLibraryModel.getKbName();
                        // 检查用户删除权限
                        checkPublicPermission(tempId);
                        ids.add(tempId);
                        kbNames.add(tempKbName);
                    }

                }
            }
        } else {
            return R.fail("必须提供文档库id或知识库名称");
        }


        // 访问chatchat并执行知识库的删除操作
        for(int i = 0; i < kbNames.size(); i++) {
            String deleteKbName = kbNames.get(i);
            Long deleteId = ids.get(i);
            boolean ccRes = knowledgeBaseService.DeleteKnowledgeBase(deleteKbName);
            if (!ccRes){
                return R.fail("知识库删除失败！===>" + deleteKbName);
            }
            boolean res = fileLibraryService.logicRemoveFileLibrary(deleteId);
            if (!res) {
                return R.fail("文档库表修改失败！===>" + deleteId.toString());
            }
        }
        Map<String, Object> data = new HashMap<>();
        data.put("deletedIds", ids);
        data.put("deletedKbNames", kbNames);
        return R.ok(data,"知识库删除成功，并已修改文档库表！");


    }


    private void checkPublicPermission(Long id){
        if (id == 1){
            if (!SecurityUtils.getRoles().contains("超级管理员")){
                throw new ServiceException("对不起，您没有权限进行此操作操作");
            }
        }
    }
}
